/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#pragma once

#include "OmenConfig.h"
#include "OmenDataTypes.h"
#include "OmenMath.h"

namespace Omen
{
    class OMEN_API Quaternion
    {
    /// Static scalary functions
    public:
        static Quaternion fromAxisAndAngle( const Vector3d& vector, Omen::Float angle ); /// <summary>Returns a new Quaternion made from given parameters</summary>
        static Quaternion fromAxisAndAngle( Omen::Float x, Omen::Float y, Omen::Float z, Omen::Float angle ); /// <summary>Returns a new Quaternion made from given parameters</summary>
        static Quaternion fromMatrix( const Omen::Matrix4x4& m );                        /// <summary> Returns a quaternion from given rotation matrix</summary>
        
        static Quaternion lookAtRotation( const Omen::Vector3d& lookAt, Omen::Vector3d& up );

        static Omen::Matrix4x4 toMatrix( const Quaternion& q );

        static Quaternion      fromEulerAngles( Omen::Float yaw, Omen::Float pitch, Omen::Float roll );
        static Omen::Vector3d  toEulerAngles( const Quaternion& q );

    public:
        Quaternion();
        Quaternion( const Omen::Float& w, const Omen::Float& x, const Omen::Float& y, const Omen::Float& z);
        Quaternion( const Omen::Float& w, const Vector3d& vector );
        ~Quaternion();

        Quaternion  conjugate() const;       /// <summary> Returns the conjugate of this Quaternion </summary>
        bool        isIdentity() const;      /// <summary> Returns true if this is an identity Quaternion </summary>

        Omen::Float  length() const;         /// <summary> Returns the length (the norm) of this Quaternion</summary>

        void normalize();                    /// <summary> Normalizes this Quaternion </summary>
        Quaternion normalized() const;       /// <summary> Returns a normalized copy of this Quaternion</summary>

        Vector3d rotatedVector( const Vector3d& vector ) const; /// <summary> Returns a vector rotated by this Quaternion in 3d space</summary>

        Vector3d vector() const;            /// <summary> Returns the vector component (x,y,z) of this Quaternions</summary>
        void     setVector( const Omen::Vector3d& vector ); /// <summary>Sets the vector part of Quaterntion by given vector</summary>

        Quaternion& operator*  ( const Quaternion& quaternion );
        Quaternion& operator*= ( Omen::Float scalar );               /// <summary>Multiplies this Quaternion by given scalar</summary>
        Quaternion& operator*= ( const Quaternion& quaternion );    /// <summary>Multiplies this Quaternion with given Quaternion</summary>
        Quaternion& operator+= ( const Quaternion& quaternion );    /// <summary>Adds given Quaternion to this Quaternion</summary>
        Quaternion& operator-= ( const Quaternion& quaternion );    /// <summary>Subtracts given Quaternion from this Quaternion</summary>
        Quaternion& operator/= ( Omen::Float scalar );               /// <summary>Divided this Quaternion by given scalar</summary>
    
    public:
        Omen::Float w,x,y,z;                                /// <summary>The w,x,y,z</summary>

        static Quaternion nlerp( const Quaternion& q1, const Quaternion& q2, Omen::Float t ); /// <summary> Returns normalized, interpolated Quaternion between q1 and q2 at given time t[0..1]</summary>
        static Quaternion slerp( const Quaternion& q1, const Quaternion& q2, Omen::Float t ); /// <summary> Returns spherical interpolated Quaternion between q1 and q2 at given time t[0..1]</summary>

    };

    /// Non Member Quaterion functions
    //bool     qFuzzyCompare ( const Quaternion& q1, const Quaternion& q2 );
    const Quaternion operator* ( const Quaternion& q1, const Quaternion& q2 );
    OMEN_API const Quaternion operator* ( Omen::Float scalar, const Quaternion& quaternion );
    OMEN_API const Quaternion operator* ( const Quaternion& quaternion, Omen::Float scalar );
    OMEN_API const Quaternion operator+ ( const Quaternion& q1, const Quaternion& q2 );
    OMEN_API const Quaternion operator- ( const Quaternion& q1, const Quaternion& q2 );
    OMEN_API const Quaternion operator- ( const Quaternion& quaternion );
    OMEN_API const Quaternion operator/ ( const Quaternion& quaternion, Omen::Float scalar );
    
    OMEN_API bool     operator!= ( const Quaternion& q1, const Quaternion& q2 );
    OMEN_API bool     operator== ( const Quaternion& q1, const Quaternion& q2 );

} // namespace Omen